package gd.qaq.blue.locationleader.listener;

import gd.qaq.blue.locationleader.LocationLeader;
import gd.qaq.blue.locationleader.api.API;
import gd.qaq.blue.locationleader.entity.TargetLocation;
import lk.vexview.api.VexViewAPI;
import lk.vexview.hud.VexTextShow;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.util.Vector;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static gd.qaq.blue.locationleader.LocationLeader.*;
import static gd.qaq.blue.locationleader.api.API.getLocationPath;

@SuppressWarnings("all")
public class LocationLeaderListener implements Listener {
    public static Map<String, TargetLocation> playerUUIDAndTarget = new HashMap<>();

    @EventHandler
    public void onJoin(PlayerJoinEvent event) {
        Player player = event.getPlayer();
        TargetLocation targetLocation = playerUUIDAndTarget.get(player.getUniqueId().toString());
        API.removeAllHuds(player);
        if (targetLocation != null) {
            targetLocation.setNextBlockIndex(0);
            targetLocation.setLastUpdateTime(System.currentTimeMillis());
            targetLocation.setRoutes(getLocationPath(player, targetLocation.getLocation()));
            if (targetLocation.isAuto()) {
                sendSubtitleToPlayer(player, "", 1);
            }
            targetLocation.setAuto(false);
        }
    }

    @EventHandler
    public void onMove(PlayerMoveEvent event) {
        Player player = event.getPlayer();
        TargetLocation location = playerUUIDAndTarget.get(player.getUniqueId().toString());
        if (location != null) {
            Location playerLocation = player.getLocation();
            Location target = location.getLocation();
            List<Location> routes = location.getRoutes();//获取玩家路线
//            if (routes != null && routes.size() > 0) {
//                int nextBlockIndex = location.getNextBlockIndex();
//                Location nextLocation = routes.get(nextBlockIndex);
//                if (Math.abs(nextLocation.getX() - playerLocation.getX()) >= 100 || Math.abs(nextLocation.getZ() - playerLocation.getZ()) >= 100) {
//                    getCardinalDirection(player, null, nextLocation);
//                    if (location.getLastUpdateTime() != null && location.getLastUpdateTime() >= 0) {
//                        if (System.currentTimeMillis() - location.getLastUpdateTime() >= 2000L) {
//                            List<Location> locationPath = getLocationPath(player, target);
////                    if (locationPath != null && locationPath.size() > 0) {
//                            routes = locationPath;
//                            location.setRoutes(routes);
//                            location.setNextBlockIndex(0);
//                            nextLocation = routes.get(location.getNextBlockIndex());  location.setLastUpdateTime(0L);
//                        }
//                    } else {
//                        location.setLastUpdateTime(System.currentTimeMillis());
//                    }
//                } else {
////                    if (System.currentTimeMillis() - location.getLastUpdateTime() >= 5000L) {
////                        List<Location> locationPath = getLocationPath(player, target);
//////                    if (locationPath != null && locationPath.size() > 0) {
////                        routes = locationPath;
////                        location.setRoutes(routes);
////                        location.setNextBlockIndex(0);
////                        nextLocation = routes.get(location.getNextBlockIndex());
//////                    }
//////                    //如果五秒玩家依然没有到达下一个目标点,可能是走偏了,则让玩家的目标索引+4
//////                    while (true) {
//////                        //判断一下该方块和玩家谁离目标点更近
//////                        nextLocation = routes.get(nextBlockIndex >= routes.size() ? (routes.size() - 1) : nextBlockIndex);
//////                        Vector nextDistance = target.clone().subtract(nextLocation).toVector();
//////                        Vector playerDistance = target.clone().subtract(player.getLocation()).toVector();
//////                        if (nextDistance.length() >= playerDistance.length()) {
//////                            //如果玩家更近,让目标块再加4
//////                            nextBlockIndex += 4;
//////                            location.setNextBlockIndex(nextBlockIndex >= routes.size() ? (routes.size() - 1) : nextBlockIndex);
//////                            if (nextBlockIndex >= routes.size()) {
//////                                //如果目标块已是最后一个,跳出循环
//////                                break;
//////                            }
//////                        } else {
////////                            success(player, "break");
//////                            //如果目标点更近,退出循环
//////                            break;
//////                        }
//////                    }
////                        //更新玩家时间
////                        location.setLastUpdateTime(System.currentTimeMillis());
////                    }
//                }
//                if (checkIsArrived(playerLocation, nextLocation, 3, 2)) {
//                    int nextIndex = nextBlockIndex + 4;
////                    location.setLastUpdateTime(System.currentTimeMillis());
//                    location.setNextBlockIndex(nextIndex >= routes.size() ? (routes.size() - 1) : nextIndex);//如果玩家到达了,格子加1
//                    nextLocation = routes.get(location.getNextBlockIndex());
////                    location.setLastUpdateTime(System.currentTimeMillis());
//                    location.setLastUpdateTime(0L);
//                }
                getCardinalDirection(player, location, target);
//            }
            if (checkIsArrived(playerLocation, target, 2, 0)) {
                jdbcUtils.remove(player);
                playerUUIDAndTarget.remove(player.getUniqueId().toString());
                sendSubtitleToPlayer(player, colorFormat(config.getString("plugin.lang.arrivedTarget").replace("%target%", location.getLocationName())));
                API.removeAllHuds(player);
            }
        }
    }

    public static boolean checkIsArrived(Location start, Location end, int range, int vierticalRange) {
        if (
                (Math.abs(start.getX() - end.getX()) <= range)
                        && (Math.abs(start.getZ() - end.getZ()) <= range)
                        && (((int) Math.abs(start.getY() - end.getY())) <= vierticalRange)) {
            return true;
        }
        return false;
    }

    public static void sendAllHuds(Player player, Vector targetVector, TargetLocation targetLocation, String direction, int needBlock, String virticalDirection) {
        VexTextShow distanceText = null;
        VexTextShow directionIcon = null;
        if (targetVector == null) {
            distanceText = new VexTextShow("distanceText",
                    LocationLeader.config.getInt("hud.player.distanceText.x"),
                    LocationLeader.config.getInt("hud.player.distanceText.y"),
                    LocationLeader.config.getInt("hud.player.distanceText.z"),
                    Arrays.asList(colorFormat("&c&l你已脱离导航路线,正在重新规划路线...")), 0,
                    LocationLeader.config.getInt("hud.player.distanceText.scale"));
            directionIcon = new VexTextShow("directionIcon",
                    LocationLeader.config.getInt("hud.player.directionIcon.x"),
                    LocationLeader.config.getInt("hud.player.directionIcon.y"),
                    LocationLeader.config.getInt("hud.player.directionIcon.z"),
                    Arrays.asList(colorFormat("&b")), 0,
                    LocationLeader.config.getInt("hud.player.directionIcon.scale"));
        } else {

            String distanceTextContent = config.getString("hud.player.distanceText.content");
            if (needBlock != 0) {
                distanceTextContent += config.getString("hud.player.distanceText.verticalIcon").replace("%vertical%", virticalDirection);
                distanceTextContent += config.getString("hud.player.distanceText.verticalDistance").replace("%vDistance%", String.valueOf(needBlock));
            }
            distanceTextContent = distanceTextContent.replace("%distance%", String.format("%.1f", targetVector.length()));
            distanceTextContent = distanceTextContent.replace("%targetName%", targetLocation.getLocationName());
            distanceText = new VexTextShow("distanceText",
                    LocationLeader.config.getInt("hud.player.distanceText.x"),
                    LocationLeader.config.getInt("hud.player.distanceText.y"),
                    LocationLeader.config.getInt("hud.player.distanceText.z"),
                    Arrays.asList(colorFormat(distanceTextContent)), 0,
                    LocationLeader.config.getInt("hud.player.distanceText.scale"));
            directionIcon = new VexTextShow("directionIcon",
                    LocationLeader.config.getInt("hud.player.directionIcon.x"),
                    LocationLeader.config.getInt("hud.player.directionIcon.y"),
                    LocationLeader.config.getInt("hud.player.directionIcon.z"),
                    Arrays.asList(colorFormat(config.getString("hud.player.directionIcon.content")
                            .replace("%direction%", direction))), 0,
                    LocationLeader.config.getInt("hud.player.directionIcon.scale"));
        }
        VexViewAPI.sendHUD(player, distanceText);
        VexViewAPI.sendHUD(player, directionIcon);
    }

    public static String getCardinalDirection(Player player) {
        double rot = (player.getLocation().getYaw() - 90) % 360;
        if (rot < 0) {
            rot += 360.0;
        }
        return getDirection(rot);
    }

    /**
     * Converts a rotation to a cardinal direction name.
     *
     * @param rot
     * @return
     */
    private static String getDirection(double rot) {
        if (0 <= rot && rot < 22.5) {
            return "North";
        } else if (22.5 <= rot && rot < 67.5) {
            return "Northeast";
        } else if (67.5 <= rot && rot < 112.5) {
            return "East";
        } else if (112.5 <= rot && rot < 157.5) {
            return "Southeast";
        } else if (157.5 <= rot && rot < 202.5) {
            return "South";
        } else if (202.5 <= rot && rot < 247.5) {
            return "Southwest";
        } else if (247.5 <= rot && rot < 292.5) {
            return "West";
        } else if (292.5 <= rot && rot < 337.5) {
            return "Northwest";
        } else if (337.5 <= rot && rot < 360.0) {
            return "North";
        } else {
            return null;
        }
    }

    public void getCardinalDirection(Player player, TargetLocation targetLocation, Location next) {
        if (targetLocation != null) {
            Location target = targetLocation.getLocation();
            Vector vector1 = target.clone().subtract(player.getLocation().clone()).toVector();
            Location location = player.getLocation().clone().setDirection(vector1);
            Vector nextVector = next.clone().subtract(player.getLocation().clone()).toVector();
            Location nextPlayerLocation = player.getLocation().clone().setDirection(nextVector);
            String direction = yawToCardinalDirection(player, nextPlayerLocation.getYaw());
            String virticalDirection = "";
            float pitch = next.getPitch();
            int needBlock = 0;
            if ((int) player.getLocation().getY() > (int) next.getY()) {
                needBlock = (int) Math.abs(player.getLocation().getY() - next.getY());
                virticalDirection = "DOWN";
            } else if ((int) player.getLocation().getY() < (int) next.getY()) {
                needBlock = (int) Math.abs(player.getLocation().getY() - next.getY());
                virticalDirection = "UP";
            } else {
                virticalDirection = "";
            }
            sendAllHuds(player, vector1, targetLocation, direction, needBlock, virticalDirection);
        } else {
            sendAllHuds(player, null, targetLocation, null, 0, null);
        }
    }

    public static String yawToCardinalDirection(Player player, double n) {
        if (0.0f <= n && n < 22.5) {
            switch (getCardinalDirection(player)) {
                case "Northwest":
                    return "↖";
                case "West":
                    return "↑";
                case "East":
                    return "↙";
                case "North":
                case "Northeast":
                    return "←";
                case "Southeast":
                    return "↓";
                case "South":
                    return "↘";
                case "Southwest":
                    return "→";
            }
        }
        if (22.5 <= n && n < 67.5) {
            switch (getCardinalDirection(player)) {
                case "Northwest":
                    return "↑";
                case "West":
                case "Southwest":
                    return "↗";
                case "North":
                    return "↖";
                case "East":
                    return "↙";
                case "Northeast":
                    return "←";
                case "Southeast":
                    return "↓";
                case "South":
                    return "↘";
            }
        }
        if (67.5 <= n && n < 112.5) {
            switch (getCardinalDirection(player)) {
                case "Northwest":
                case "West":
                    return "→";
                case "North":
                    return "↑";
                case "East":
                case "Northeast":
                case "Southeast":
                    return "←";
                case "South":
                case "Southwest":
                    return "↓";
            }
        }
        if (112.5 <= n && n < 157.5) {
            switch (getCardinalDirection(player)) {
                case "Northwest":
                case "North":
                    return "→";
                case "West":
                case "Southwest":
                    return "↓";
                case "East":
                    return "↖";
                case "Northeast":
                    return "↑";
                case "Southeast":
                case "South":
                    return "←";
            }
        }
        if (157.5 <= n && n < 202.5) {
            switch (getCardinalDirection(player)) {
                case "Northwest":
                    return "↘";
                case "West":
                    return "↓";
                case "North":
                    return "→";
                case "Northeast":
                    return "↗";
                case "East":
                    return "↑";
                case "Southeast":
                    return "↖";
                case "Southwest":
                    return "↙";
                case "South":
                    return "←";
            }
        }
        if (202.5 <= n && n < 247.5) {
            switch (getCardinalDirection(player)) {
                case "Northwest":
                    return "↓";
                case "North":
                    return "↘";
                case "East":
                    return "↗";
                case "Northeast":
                    return "→";
                case "Southeast":
                    return "↑";
                case "South":
                    return "↖";
                case "Southwest":
                    return "←";
                case "West":
                    return "↙";
            }
        }
        if (247.5 <= n && n < 292.5) {
            switch (getCardinalDirection(player)) {
                case "North":
                    return "↓";
                case "Northeast":
                    return "↘";
                case "East":
                    return "→";
                case "Southeast":
                    return "↗";
                case "Southwest":
                    return "↖";
                case "South":
                    return "↑";
                case "West":
                    return "←";
                case "Northwest":
                    return "↙";
            }
        }
        if (292.5 <= n && n < 337.5) {
            switch (getCardinalDirection(player)) {
                case "North":
                    return "↙";
                case "Northeast":
                    return "↓";
                case "Southwest":
                    return "↑";
                case "South":
                    return "↗";
                case "East":
                    return "↘";
                case "Southeast":
                    return "→";
                case "West":
                    return "↖";
                case "Northwest":
                    return "←";
            }
        }
        if (337.5 <= n && n < 360.0) {
            switch (getCardinalDirection(player)) {
                case "West":
                    return "↑";
                case "Southwest":
                    return "↗";
                case "East":
                    return "↓";
                case "Northeast":
                    return "↙";
                case "North":
                    return "←";
                case "Northwest":
                    return "↖";
                case "Southeast":
                    return "↘";
                case "South":
                    return "→";
            }
        }
        return "未知";
    }
}
